#ifndef __PTGUI_EVENT_H__
#define __PTGUI_EVENT_H__

#include <ptgui/ptgui.h>
#include <ptgui/kbddef.h>

struct ptgui_msgqueue
{
	ptgui_list_t list;			/* mq list */

	void* msg_pool;			/* start address of message queue. */

	rt_size_t msg_size;		/* message size of each message. */
	rt_size_t max_msgs;		/* max number of messages. */

	void* msg_queue_head;	/* list head. */
	void* msg_queue_tail;	/* list tail. */
	void* msg_queue_free;	/* pointer indicated the free node of queue. */

	rt_ubase_t entry;		/* index of messages in the queue. */
};
typedef struct ptgui_msgqueue* ptgui_msgqueue_t;
void ptgui_msgqueue_system_init();
pt_status_t ptgui_msgqueue_init(ptgui_msgqueue_t mq, void *msgpool, rt_size_t msg_size, rt_size_t pool_size);
pt_status_t ptgui_msgqueue_detach(ptgui_msgqueue_t mq);
ptgui_msgqueue_t ptgui_msgqueue_create (const char* name, rt_size_t msg_size, rt_size_t max_msgs);
pt_status_t ptgui_msgqueue_delete (ptgui_msgqueue_t mq);
pt_status_t ptgui_msgqueue_send (ptgui_msgqueue_t mq, void* buffer, rt_size_t size);
pt_status_t ptgui_msgqueue_urgent(ptgui_msgqueue_t mq, void* buffer, rt_size_t size);
pt_status_t ptgui_msgqueue_recv(ptgui_msgqueue_t mq, void* buffer, rt_size_t size);

enum _ptgui_event_type
{
	PTGUI_EVENT_TIMER,
	/* timer 				*/
	PTGUI_EVENT_RENDER,
	/* paint on screen 		*/
	PTGUI_EVENT_FRAME,
	/* frame on screen 		*/

	/* mouse and keyboard event */
	PTGUI_EVENT_MOUSE_MOTION,
	/* mouse motion */
	PTGUI_EVENT_MOUSE_BUTTON,
	/* mouse button info 	*/
	PTGUI_EVENT_KBD,
	/* keyboard info		*/
	PTGUI_EVENT_TOUCH_KEY,
	/* keyboard info		*/
	/* user command event */
	PTGUI_EVENT_COMMAND,
	/* user command 		*/
};

typedef enum _ptgui_event_type ptgui_event_type;

enum
{
	PTGUI_STATUS_OK	= 0,
	/* status ok 		*/
	PTGUI_STATUS_ERROR,
	/* generic error 	*/
	PTGUI_STATUS_NRC,
	/* no resource 		*/
};

struct ptgui_event
{
	/* the event type */
	rt_uint16_t id;

	/* user field of event */
	ptgui_widget_t	*src;

	/* the event sender */
	ptgui_widget_t	*dest;

	union
	{
		void			*p; 		   /* Some messages need more info ... */
		rt_uint32_t		v;
		ptgui_color_t	color;
	} data;

	/* mailbox to acknowledge request */
	rt_mailbox_t	ack;
};

#define PTGUI_EVENT(e)	((struct ptgui_event*)(e))

#define PTGUI_EVENT_INIT(e, t)	do		\
{										\
	(e)->id = (t);					\
	(e)->src = NULL;						\
	(e)->dest = NULL;		\
	(e)->data.v = 0;		\
	(e)->ack = RT_NULL;					\
} while (0)

struct ptgui_timer;
struct ptgui_event_timer
{
	struct ptgui_event	parent;

	struct ptgui_timer	*timer;
};
#define PTGUI_EVENT_TIMER_INIT(e)			PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_TIMER)

struct ptgui_event_paint
{
	struct ptgui_event	parent;

	ptgui_scene_t		*wid;		/* destination widget */
};

#define PTGUI_EVENT_PAINT_INIT(e)			PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_RENDER)

struct ptgui_event_frame
{
	struct ptgui_event	parent;

	rt_uint32_t		delta;		/* destination widget */
};

#define PTGUI_EVENT_FRAME_INIT(e)			PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_FRAME)

/*
 * RTGUI Mouse and Keyboard Event
 */
struct ptgui_event_mouse
{
	struct ptgui_event	parent;

	ptgui_scene_t		*wid;		/* destination widget */

	rt_uint16_t			x,
						y;
	rt_uint16_t			button;
};
#define PTGUI_MOUSE_BUTTON_LEFT			0x01
#define PTGUI_MOUSE_BUTTON_RIGHT		0x02
#define PTGUI_MOUSE_BUTTON_MIDDLE		0x03
#define PTGUI_MOUSE_BUTTON_WHEELUP		0x04
#define PTGUI_MOUSE_BUTTON_WHEELDOWN	0x08

#define PTGUI_MOUSE_BUTTON_DOWN			0x10
#define PTGUI_MOUSE_BUTTON_UP			0x20

struct ptgui_event_kbd
{
	struct ptgui_event	parent;

	ptgui_scene_t		*wid;		/* destination widget */

	rt_uint16_t			type;		/* key down or up */
	rt_uint16_t			key;		/* current key */
	rt_uint16_t			mod;		/* current key modifiers */
	rt_uint16_t			unicode;	/* translated character */
};

struct ptgui_event_touch
{
	struct ptgui_event	parent;

	rt_uint16_t			type;		/* key down or up */
	rt_uint16_t			x;			/* current key */
	rt_uint16_t			y;			/* current key modifiers */
	rt_uint16_t			press;		/* translated character */
};

#define PTGUI_KBD_IS_SET_CTRL(e)	((e)->mod & (PTGUI_KMOD_LCTRL | PTGUI_KMOD_RCTRL)))
#define PTGUI_KBD_IS_SET_ALT(e)		((e)->mod & (PTGUI_KMOD_LALT  | PTGUI_KMOD_RALT))
#define PTGUI_KBD_IS_SET_SHIFT(e)	((e)->mod & (PTGUI_KMOD_LSHIFT| PTGUI_KMOD_RSHIFT))
#define PTGUI_KBD_IS_UP(e)			((e)->type == PTGUI_KEYUP)
#define PTGUI_KBD_IS_DOWN(e)		((e)->type == PTGUI_KEYDOWN)

#define PTGUI_EVENT_MOUSE_MOTION_INIT(e)	PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_MOUSE_MOTION)
#define PTGUI_EVENT_MOUSE_BUTTON_INIT(e)	PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_MOUSE_BUTTON)
#define PTGUI_EVENT_KBD_INIT(e)				PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_KBD)
#define PTGUI_EVENT_TOUCH_KEY_INIT(e)		PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_TOUCH_KEY)

struct ptgui_event_command
{
	struct ptgui_event	parent;

	/* command type */
	rt_int32_t			type;

	/* command id */
	rt_int32_t			command_id;

	/* command string */
	char				command_string[PTGUI_NAME_MAX];
};
#define PTGUI_EVENT_COMMAND_INIT(e)	PTGUI_EVENT_INIT(&((e)->parent), PTGUI_EVENT_COMMAND)

#define PTGUI_CMD_UNKNOWN		0x00
#define PTGUI_CMD_WM_CLOSE		0x10

#define PTGUI_CMD_USER_INT		0x20
#define PTGUI_CMD_USER_STRING	0x21

#endif
